package com.mail.pop3;

import java.io.IOException;
import java.net.Socket;

/**
 * This class is used to get Sockets. Depending on the arguments passed it will
 * either return a plain java.net.Socket or dynamically load the SocketFactory
 * class specified in the classname param and return a socket created by that
 * SocketFactory.
 * 
 * @author Max Spivak
 * @author Bill Shannon
 */
public class SocketFetcher implements Runnable {
	private Socket socket;
	private String host;
	private int port;

	private boolean aborted = false; // tells connection thread to close socket

	private SocketFetcher(String host, int port, int cto) throws IOException {
		this.host = host;
		this.port = port;
	}

	/**
	 * 
	 * @param host
	 *            The host to connect to
	 * @param port
	 *            The port to connect to at the host
	 */
	public static Socket getSocket(String host, int port) throws IOException {

		return getSocket0(host, port);

	}

	/**
	 * This method deals with all the hard work of handling the socket factory
	 * class, and then making the connection. Note that to avoid a static
	 * dependency on the javax.net.SocketFactory class we use reflection to
	 * invoke the socket factory.
	 */
	private static Socket getSocket0(String host, int port) throws IOException {
		Socket socket = new Socket(host, port);

		return socket;
	}

	/**
	 * Try to open the connection, and only when done synchronize with the main
	 * "getSocket" thread and return our result.
	 */
	public void run() {
		try {
			Socket s = getSocket0(host, port);
			synchronized (this) {
				if (aborted) {
					// getSocket thread gave up waiting,
					// we have to close the socket
					try {
						s.close();
					} catch (IOException ex) {
					}
				} else
					socket = s;
				notify(); // wakeup getSocket thread
			}
		} catch (IOException ex) {
			synchronized (this) {
				notify(); // wakeup getSocket thread
			}
		}
	}

	protected synchronized void finalize() throws IOException {
		/*
		 * Paranoia. This should never happen, but just in case we get here
		 * without the socket being closed, close it.
		 */
		if (socket != null)
			socket.close(); // just in case
	}
}
